/*
 * @Author: jingfuu@163.com
 * @Date: 2024-12-04 14:30:27
 * @LastEditTime: 2024-12-04 14:30:28
 * @Description: 获取ip地址工具类
 */
import { Request } from 'express';
import os from 'os';

/**
 * 获取客户端 IP 地址工具类
 */
class IpUtils {
  private static readonly IP_UTILS_FLAG = ',';
  private static readonly UNKNOWN = 'unknown';
  private static readonly LOCALHOST_IP = '0:0:0:0:0:0:0:1';
  private static readonly LOCALHOST_IP1 = '127.0.0.1';

  /**
   * 获取IP地址
   * @param req - Express 请求对象
   * @returns 客户端的真实 IP 地址
   */
  public static getIpAddr(req: Request): string | null {
    let ip = this.getHeaderValue(req, 'X-Original-Forwarded-For');
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'X-Forwarded-For');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'x-forwarded-for');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'Proxy-Client-IP');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'WL-Proxy-Client-IP');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'HTTP_CLIENT_IP');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = this.getHeaderValue(req, 'HTTP_X_FORWARDED_FOR');
    }
    if (this.isEmptyOrUnknown(ip)) {
      ip = req.ip || req.connection.remoteAddress;
      if (ip === IpUtils.LOCALHOST_IP1 || ip === IpUtils.LOCALHOST_IP) {
        // 根据网卡获取本机配置的IP
        ip = this.getLocalIp();
      }
    }

    // 使用代理，则获取第一个IP地址
    if (!this.isEmptyOrUnknown(ip) && ip.includes(IpUtils.IP_UTILS_FLAG)) {
      ip = ip.split(IpUtils.IP_UTILS_FLAG)[0].trim();
    }

    return ip || null;
  }

  private static getHeaderValue(
    req: Request,
    header: string,
  ): string | undefined {
    return req.headers[header.toLowerCase()] as string | undefined;
  }

  private static isEmptyOrUnknown(value: string | undefined): boolean {
    return !value || value.toLowerCase() === IpUtils.UNKNOWN;
  }

  private static getLocalIp(): string | undefined {
    const interfaces = os.networkInterfaces();
    for (const interfaceName in interfaces) {
      const iface = interfaces[interfaceName];
      if (iface) {
        for (const alias of iface) {
          if (alias.family === 'IPv4' && !alias.internal) {
            return alias.address;
          }
        }
      }
    }
    return undefined;
  }
}

export default IpUtils;
